﻿using Sidvall.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;

namespace Sidvall.Data
{
    public class BusinessRule : INotifyPropertyChanged
    {
        #region Public Members

        public event PropertyChangedEventHandler PropertyChanged;

        public string RuleGroupName { get; set; }
        public string RuleName { get; set; }
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
        public NameCollection AffectedProperties { get; set; }
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
        public NameCollection Categories { get; set; }

        #region Priority

        private int _Priority;
        public int Priority
        {
            get
            {
                return _Priority;
            }
            set
            {
                if (value < 0)
                    value = 0;
                if (_Priority == value)
                    return;
                _Priority = value;
                OnPropertyChanged(nameof(Priority));
            }
        }

        #endregion
        #region Description

        private string _Description;
        public string Description
        {
            get
            {
                return _Description;
            }
            set
            {
                if (_Description == value)
                    return;
                _Description = value;
                OnPropertyChanged(nameof(Description));
            }
        }

        #endregion
        #region Severity

        private RuleSeverity _Severity;
        public RuleSeverity Severity
        {
            get
            {
                return _Severity;
            }
            set
            {
                if (_Severity == value)
                    return;
                _Severity = value;
                OnPropertyChanged(nameof(Severity));
            }
        }

        #endregion
        #region IsBroken

        private bool _IsBroken;
        public bool IsBroken
        {
            get
            {
                return _IsBroken;
            }
            set
            {
                if (_IsBroken == value)
                    return;
                _IsBroken = value;
                OnPropertyChanged(nameof(IsBroken));
            }
        }

        #endregion

        #region AddAffectedProperties

        public BusinessRule AddAffectedProperties(IEnumerable<string> items)
        {
            if (this.AffectedProperties == null)
                this.AffectedProperties = new NameCollection();
            this.AffectedProperties.AddRange(items, true);
            return this;
        }
        public BusinessRule AddAffectedProperties(params string[] items)
        {
            return AddAffectedProperties(items.AsEnumerable());
        }

        #endregion
        #region AddCategories

        public BusinessRule AddCategories(IEnumerable<string> items)
        {
            if (this.Categories == null)
                this.Categories = new NameCollection();
            this.Categories.AddRange(items, true);
            return this;
        }
        public BusinessRule AddCategories(params string[] items)
        {
            return AddCategories(items.AsEnumerable());
        }

        #endregion
        #region Copy

        public BusinessRule Copy()
        {
            var item = new BusinessRule()
            {
                RuleGroupName = this.RuleGroupName,
                RuleName = this.RuleName,
                AffectedProperties = this.AffectedProperties.Copy(),
                Categories = this.Categories.Copy(),
                _Description = this.Description,
                _IsBroken = this.IsBroken,
                _Priority = this.Priority,
                _Severity = this.Severity,
            };
            return item;
        }

        #endregion
        #region HasAnyCategory

        public bool HasAnyCategory(params string[] categories)
        {
            return HasAnyCategory(categories.AsEnumerable());
        }
        public bool HasAnyCategory(IEnumerable<string> categories)
        {
            if ((categories == null) || (!categories.Any()))
            {
                if ((this.Categories == null) || (this.Categories.Count == 0))
                    return true;
                return false;
            }
            var index = categories.ToHashSet(o => o, true);
            if (this.Categories != null)
            {
                foreach (var category in this.Categories)
                {
                    if (index.Contains(category))
                        return true;
                }
            }
            return false;
        }

        #endregion
        #region Merge

        public bool Merge(BusinessRule item)
        {
            if (item == null)
                return false;

            bool updated = false;
            if (this.RuleGroupName != item.RuleGroupName)
            {
                this.RuleGroupName = item.RuleGroupName;
                updated = true;
            }
            if (this.RuleName != item.RuleName)
            {
                this.RuleName = item.RuleName;
                updated = true;
            }
            if (this.Description != item.Description)
            {
                this.Description = item.Description;
                updated = true;
            }
            if (this.Severity != item.Severity)
            {
                this.Severity = item.Severity;
                updated = true;
            }
            if (this.IsBroken != item.IsBroken)
            {
                this.IsBroken = item.IsBroken;
                updated = true;
            }
            if (this.Priority != item.Priority)
            {
                this.Priority = item.Priority;
                updated = true;
            }
            if (item.AffectedProperties != null)
            {
                if (this.AffectedProperties == null)
                    this.AffectedProperties = new NameCollection();
                if (this.AffectedProperties.Merge(item.AffectedProperties, o => o, null, null, null, true, true))
                    updated = true;
            }
            if (item.Categories != null)
            {
                if (this.Categories == null)
                    this.Categories = new NameCollection();
                if (this.Categories.Merge(item.Categories, o => o, null, null, null, true, true))
                    updated = true;
            }

            return updated;
        }

        #endregion
        #region ToString

        public override string ToString()
        {
            return this.Description;
        }

        #endregion

        #region OnPropertyChanged

        protected void OnPropertyChanged(string propertyName)
        {
            OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
        }
        protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)
        {
            if (this.PropertyChanged != null)
                this.PropertyChanged.Invoke(this, args);
        }

        #endregion

        #endregion
    }
}
